home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / news / readers / slnr / part1 < prev    next >
Encoding:
Internet Message Format  |  1993-08-11  |  61.4 KB

  1. From pgoujard@infocom.co.uk Wed Aug 11 23:30:51 1993
  2. Path: uunet!wupost!howland.reston.ans.net!agate!doc.ic.ac.uk!uknet!infocom.co.uk!pgoujard
  3. From: pgoujard@infocom.co.uk (Philippe Goujard)
  4. Newsgroups: alt.sources
  5. Subject: SLNR v1.2.c an offline newsreader 1/3
  6. Summary: Sources of the packet creator and offline newsreader
  7. Keywords: usenet offline newsreader
  8. Message-ID: <21528@infocom.co.uk>
  9. Date: 12 Aug 93 00:20:08 GMT
  10. Followup-To: alt.usenet.offline-reader
  11. Organization: INFOCOM Public Access Unix, (ModemLine) +44 [0] 734 340055
  12. Lines: 2225
  13. X-Newsreader: TIN [version 1.1 PL9]
  14. Xref: uunet alt.sources:9100
  15.  
  16. Archive-name: slnr_12c
  17. Submitted-by: pgoujard@infocom.co.uk
  18.  
  19.  
  20. The SLNR package is an off-line usenet news reader : it is intended for users
  21. who want to connect to a host, download a packet with new messages, read
  22. them on their home machine and upload the replies later.
  23.  
  24. Slnr stands for "Simple Local News Reader" 
  25.  
  26. The slnr package contains the following files
  27.  
  28. - getnews.c : This program runs on your unix machine and get all unread 
  29. articles in all subscribed newsgroups as well as your new mail and creates a 
  30. packet (.zip, .arc, .zoo) that you can download and view with slnr.
  31.  
  32. - slnr.c : The offline news reader which runs on your local machine and let 
  33. you view and reply to messages. So far there is a Unix, Dos and Atari 
  34. version.
  35.  
  36. - postreply.c : Like getnews this program runs on unix machine and post mail
  37. and news articles from the reply packet.
  38.  
  39. - colour.h : needed in slnr.c
  40.  
  41. - sig.txt  : optional signature to be appended at the end of your messages
  42.  
  43. - slnp.fmt : The packet format
  44.  
  45. - slnr.doc : First try at a documentation
  46.  
  47.  
  48. ============================================================================
  49.  
  50. #!/bin/sh
  51. # This is a shell archive (shar 3.47)
  52. # made 08/11/1993 20:01 UTC by ppg@ozz
  53. # Source directory /big/ppg/News/unix/src/slnr
  54. #
  55. # existing files will NOT be overwritten unless -c is specified
  56. #
  57. # This is part 1 of a multipart archive                                    
  58. # do not concatenate these parts, unpack them in order with /bin/sh        
  59. #
  60. # This shar contains:
  61. # length  mode       name
  62. # ------ ---------- ------------------------------------------
  63. #    283 -r--r----- slnr/vcslnr
  64. #     25 -r--r----- slnr/slnr.ver
  65. #   4233 -r--r----- slnr/README
  66. #    594 -r--r----- slnr/colour.h
  67. #  24574 -r--r----- slnr/getnews.c
  68. #   4409 -r--r----- slnr/postreply.c
  69. #     51 -r--r----- slnr/sig.txt
  70. #  28248 -r--r----- slnr/slnp.fmt
  71. #  39079 -r--r----- slnr/slnr.c
  72. #  17155 -r--r----- slnr/slnr.doc
  73. #    273 -r--r----- slnr/slnr.ini
  74. #   8581 -r--r----- slnr/getnews.doc
  75. #   2093 -rw-rw---- slnr/a
  76. #
  77. if test -r _shar_seq_.tmp; then
  78.     echo 'Must unpack archives in sequence!'
  79.     echo Please unpack part `cat _shar_seq_.tmp` next
  80.     exit 1
  81. fi
  82. # ============= slnr/vcslnr ==============
  83. if test ! -d 'slnr'; then
  84.     echo 'x - creating directory slnr'
  85.     mkdir 'slnr'
  86. fi
  87. if test -f 'slnr/vcslnr' -a X"$1" != X"-c"; then
  88.     echo 'x - skipping slnr/vcslnr (File already exists)'
  89.     rm -f _shar_wnt_.tmp
  90. else
  91. > _shar_wnt_.tmp
  92. echo 'x - extracting slnr/vcslnr (Text)'
  93. sed 's/^X//' << 'SHAR_EOF' > 'slnr/vcslnr' &&
  94. Module README version 1.6
  95. Module colour.h version 1.1
  96. Module getnews.c version 1.7
  97. Module postreply.c version 1.3
  98. Module sig.txt version 1.1
  99. Module slnp.fmt version 1.1
  100. Module slnr.c version 2.11
  101. Module slnr.doc version 1.4
  102. Module slnr.ini version 1.1
  103. Module getnews.doc version 1.5
  104. SHAR_EOF
  105. chmod 0440 slnr/vcslnr ||
  106. echo 'restore of slnr/vcslnr failed'
  107. Wc_c="`wc -c < 'slnr/vcslnr'`"
  108. test 283 -eq "$Wc_c" ||
  109.     echo 'slnr/vcslnr: original size 283, current size' "$Wc_c"
  110. rm -f _shar_wnt_.tmp
  111. fi
  112. # ============= slnr/slnr.ver ==============
  113. if test -f 'slnr/slnr.ver' -a X"$1" != X"-c"; then
  114.     echo 'x - skipping slnr/slnr.ver (File already exists)'
  115.     rm -f _shar_wnt_.tmp
  116. else
  117. > _shar_wnt_.tmp
  118. echo 'x - extracting slnr/slnr.ver (Text)'
  119. sed 's/^X//' << 'SHAR_EOF' > 'slnr/slnr.ver' &&
  120. Project slnr version 1.1
  121. SHAR_EOF
  122. chmod 0440 slnr/slnr.ver ||
  123. echo 'restore of slnr/slnr.ver failed'
  124. Wc_c="`wc -c < 'slnr/slnr.ver'`"
  125. test 25 -eq "$Wc_c" ||
  126.     echo 'slnr/slnr.ver: original size 25, current size' "$Wc_c"
  127. rm -f _shar_wnt_.tmp
  128. fi
  129. # ============= slnr/README ==============
  130. if test -f 'slnr/README' -a X"$1" != X"-c"; then
  131.     echo 'x - skipping slnr/README (File already exists)'
  132.     rm -f _shar_wnt_.tmp
  133. else
  134. > _shar_wnt_.tmp
  135. echo 'x - extracting slnr/README (Text)'
  136. sed 's/^X//' << 'SHAR_EOF' > 'slnr/README' &&
  137. README FILE
  138. Version : 1.6
  139. X
  140. What is SLNR ?
  141. ~~~~~~~~~~~~~~
  142. The SLNR package is an off-line usenet news reader : it is intended for users
  143. who want to connect to a host, download a packet with new messages, read
  144. them on their home machine and upload the replies later.
  145. X
  146. Slnr stands for "Simple Local News Reader" 
  147. X
  148. The slnr package contains the following files
  149. X
  150. - getnews.c : This program runs on your unix machine and get all unread 
  151. articles in all subscribed newsgroups as well as your new mail and creates a 
  152. packet (.zip, .arc, .zoo) that you can download and view with slnr.
  153. X
  154. - slnr.c : The offline news reader which runs on your local machine and let 
  155. you view and reply to messages. So far there is a Unix, Dos and Atari 
  156. version.
  157. X
  158. - postreply.c : Like getnews this program runs on unix machine and post mail
  159. and news articles from the reply packet.
  160. X
  161. - colour.h : needed in slnr.c
  162. X
  163. - sig.txt  : optional signature to be appended at the end of your messages
  164. X
  165. - slnp.fmt : The packet format
  166. X
  167. - slnr.doc : First try at a documentation
  168. X
  169. X
  170. What are my objectives ?
  171. ~~~~~~~~~~~~~~~~~~~~~~~~
  172. X  - The specification for the format and the sources of getnews and slnr 
  173. X  will be widely available and in the public domain. (unlike QWK where the 
  174. X  format is cryptic).
  175. X  
  176. X  - There wont be any restriction for people who want to make shareware or 
  177. X  commercial version of the software. 
  178. X  
  179. X  - There will be a "version" scheme : The packet format should stay the 
  180. X  same but even if it has to be altered the version will be noted in the 
  181. X  packet so future readers can extract information properly.
  182. X  
  183. X  - Development on multiple platforms will be encouraged (specially Mac and 
  184. X  Amigas where I don't have access). However I will keep the master source 
  185. X  and will decide how to integrate the updates and bug fixes I receive.
  186. X  
  187. X  - I will also encourage translations of the doc and the user interface (I 
  188. X  can work on the french version though :-) ).
  189. X  
  190. X
  191. Where to go from there ?
  192. ~~~~~~~~~~~~~~~~~~~~~~~~
  193. X   
  194. X   - Compile and test the product on your machine (you don't really need a
  195. X   makefile but feel free to write one if it helps).
  196. X
  197. X   On the unix machine : compile getnews.c and postreply.c. You may have to
  198. X   modify them for your system. Read the getnews.doc documentation and
  199. X   create a .getnewsrc config file to suit your needs.
  200. X
  201. X   On the dos/atari/etc... machine : Compile slnr.c, maybe create a "batch"
  202. X   program to extract the files from the packet.
  203. X
  204. X   - Send comments or bug report to me <pgoujard@infocom.co.uk>
  205. X
  206. X   - If you are interested in SLNR and other off-line news reader, 
  207. X   read the usenet newsgroup : alt.usenet.offline-reader
  208. X
  209. X
  210. Changes since the previous issues
  211. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  212. X
  213. - 23/05/93 : Start of slnr v2.0. Adding "#ifdef __STDC__" to cope with non
  214. ansi compilers.
  215. X
  216. - SLNR : Fixing the mail/posting bug: creation of a special area
  217. RMAIL.MSG which contains all replies by mail.
  218. X
  219. - SLNR : Accepting files which are at the mail or MMDF format. 
  220. X
  221. - SLNR : Add the "LINES" entry in the config file (however on a dos machine 
  222. it does not put the machine in that line mode, it just tells SLNR that
  223. there are more lines to use).
  224. X
  225. - SLNR : Change the #ifdef DOS to #ifdef __MSDOS__
  226. X
  227. - Getnews : Print a "." only every 10 articles.
  228. X
  229. - Getnews : If Delete_mailbox is unset, save the content of the mailbox to
  230. the $HOME/.oldmail file
  231. X
  232. - Getnews : Fix a bug that was allowing to close stderr.
  233. X
  234. - Getnews : Change the way the compression utility is used. The config file
  235. has to have an entry called "compress=" pointing to the program doing the
  236. compression and packing. By default /usr/local/bin/zip is used.
  237. X
  238. - Getnews : Add support for a configuration file + creation of getnews.doc
  239. X
  240. - SLNR : support the "quote" entry in the config file
  241. X
  242. - SLNR : Allow header editing for replies.
  243. X
  244. - SLNR : Add the "so.and.so wrote:" line in top of follow-ups
  245. X
  246. - SLNR : Add 's' and 'S' command to save an article to a file
  247. X
  248. - SLNR : Add '!' command to execute a shell program.
  249. X
  250. Thanks to
  251. ~~~~~~~~~
  252. X       - Bob Rusbasan <rrusbassa@nyx.cs.du.edu> for carrying on intensive 
  253. X       tests on the dos version of SLNR and for his overall support.
  254. X
  255. X       - Dick Grady <grady@world.std.com> for helping with getnews.c
  256. SHAR_EOF
  257. chmod 0440 slnr/README ||
  258. echo 'restore of slnr/README failed'
  259. Wc_c="`wc -c < 'slnr/README'`"
  260. test 4233 -eq "$Wc_c" ||
  261.     echo 'slnr/README: original size 4233, current size' "$Wc_c"
  262. rm -f _shar_wnt_.tmp
  263. fi
  264. # ============= slnr/colour.h ==============
  265. if test -f 'slnr/colour.h' -a X"$1" != X"-c"; then
  266.     echo 'x - skipping slnr/colour.h (File already exists)'
  267.     rm -f _shar_wnt_.tmp
  268. else
  269. > _shar_wnt_.tmp
  270. echo 'x - extracting slnr/colour.h (Text)'
  271. sed 's/^X//' << 'SHAR_EOF' > 'slnr/colour.h' &&
  272. /*
  273. ** Module        : colour.h
  274. ** Author        : P.Goujard
  275. ** Started       : 22/01/93
  276. ** Version       : 1.1
  277. ** Last modified : 23 May 1993
  278. */
  279. #ifndef ATARI
  280. #define HOME "[H"                 /* home the cursor */
  281. #define CLS "[2J"                 /* clear the screen */
  282. #endif
  283. X
  284. #define BLACK   0
  285. #define RED     1
  286. #define GREEN   2
  287. #define YELLOW  3
  288. #define BLUE    4
  289. #define MAGENTA 5
  290. #define CYAN    6
  291. #define WHITE   7
  292. #define NONE    8
  293. #define MAX_CLR 20
  294. X
  295. #define RESET 0
  296. #define HIGH  1
  297. #define BLINK 5
  298. X
  299. X
  300. #define COL_HEAD "["
  301. X
  302. char *scr(int attribute,int foreground, int background);
  303. SHAR_EOF
  304. chmod 0440 slnr/colour.h ||
  305. echo 'restore of slnr/colour.h failed'
  306. Wc_c="`wc -c < 'slnr/colour.h'`"
  307. test 594 -eq "$Wc_c" ||
  308.     echo 'slnr/colour.h: original size 594, current size' "$Wc_c"
  309. rm -f _shar_wnt_.tmp
  310. fi
  311. # ============= slnr/getnews.c ==============
  312. if test -f 'slnr/getnews.c' -a X"$1" != X"-c"; then
  313.     echo 'x - skipping slnr/getnews.c (File already exists)'
  314.     rm -f _shar_wnt_.tmp
  315. else
  316. > _shar_wnt_.tmp
  317. echo 'x - extracting slnr/getnews.c (Text)'
  318. sed 's/^X//' << 'SHAR_EOF' > 'slnr/getnews.c' &&
  319. /* 
  320. **  Project       : Simple Local News Reader 
  321. **
  322. **    Name          : GETNEWS
  323. **  Version       : 1.7
  324. **
  325. **    Author        : P.Goujard
  326. **    Started       : 22/01/93
  327. **  Last modified : 11 Aug 1993
  328. **    Goal          : Getting unread Mail and News articles from the spool
  329. **                        directory and putting them in a SLNP file
  330. */
  331. X
  332. #include <stdio.h>
  333. #include <string.h>
  334. #include <sys/types.h>
  335. #include <sys/stat.h>
  336. #include <time.h>
  337. #include <unistd.h>
  338. #include <ctype.h>
  339. #include <stdlib.h>
  340. #include <dirent.h>
  341. X
  342. #define UNSET 0
  343. #define SET   1
  344. #define ASK   2
  345. X
  346. /* Values returned by lfgets() */
  347. #define LFGETS_OK    0
  348. #define LFGETS_EOF   1
  349. #define LFGETS_ERR   2
  350. X
  351. X
  352. #ifdef INFOCOM
  353. #include "new.h"
  354. #endif
  355. X
  356. /*
  357. ** Change those values to the one in your system
  358. */
  359. X
  360. /*
  361. ** Usually on unix a user has a file called ".newsrc" in his home
  362. ** directory. 
  363. ** This file is created by newsreaders like, rn,nn,vn,tin,tass,trn
  364. ** and contains the list of newsgroups and last read pointers
  365. */
  366. #define NEWSRC ".newsrc"
  367. X
  368. /*
  369. ** nrc2 is the name of the temporary .newsrc 
  370. ** You shouldn't need to change it
  371. */
  372. #define NRC2   "nrc2"
  373. X
  374. /*
  375. ** LOGDIR is the directory where error and log files are created
  376. ** Usually /tmp or /usr/tmp
  377. */
  378. #ifdef INFOCOM
  379. #define LOGDIR "/server/logfiles"
  380. #else
  381. #define LOGDIR "/usr/tmp"
  382. #endif
  383. #define LOGFILE "getnews.log"
  384. X
  385. /*
  386. ** Under MMDF, a mailbox consists of messages separated by 4 Ctrl A
  387. ** Normal mailboxes just use the "From " line as separator
  388. */
  389. #define MMDF_SEPARATOR ""
  390. X
  391. /*
  392. ** SPOOL is the directory where the news are located
  393. ** This has no effect with NNTP
  394. ** GROUPS is the file containing the description of each newsgroup
  395. */
  396. #define SPOOL "/usr/spool/news"
  397. #define GROUPS "/usr/lib/news/newsgroups"
  398. X
  399. /*
  400. ** The following names are consistent with the 
  401. ** SLNP & Helldiver packet format.
  402. ** You shouldn't need to change them.
  403. ** For more info report to the file slnp.fmt
  404. */
  405. #define NEWSTXT ".MSG"
  406. #define AREALIST "AREAS"
  407. X
  408. /*
  409. ** PACKETNAME is used to define the first part of the name of the packet
  410. ** the extension is taken fron the compression used
  411. */
  412. #define PACKETNAME "SLNP"
  413. X
  414. X
  415. /* Prototypes */
  416. X
  417. #ifdef __STDC__
  418. X
  419. unsigned long add_file(char *f1,char *f2, int headermode);
  420. char *get_description(char *group,char *text);
  421. void dot2slash(char *line);
  422. int is_unread(int message_no,char *list_read,int last);
  423. int get_token(char *line,char **tlist,char **pos);
  424. char *upperit(char *line);
  425. int su_get( char *line, char *pos);
  426. int sua_get(char *line, char *pos);
  427. void index_message(int area,char *message,unsigned long offset);
  428. int exp_env(char *s);
  429. int lfgets(char **s, int *ns, FILE *stream);
  430. X
  431. #else
  432. X
  433. unsigned long add_file();
  434. char *get_description();
  435. void dot2slash();
  436. int is_unread();
  437. int get_token();
  438. char *upperit();
  439. int su_get();
  440. int sua_get();
  441. void index_message();
  442. int exp_env();
  443. int lfgets();
  444. X
  445. #define remove unlink
  446. X
  447. #endif
  448. void read_config();
  449. X
  450. /*
  451. ** Global variables
  452. */
  453. int Msgmax,Grpmax,Mmdf,Usenet_only,
  454. X    Mail_only,Delete_mailbox,Get_mail,Mark_read,Do_index,Index_only;
  455. char Compress[80],Packet_name[80],Work_dir[80],Arctype[10];
  456. X
  457. int main (int argc, char *argv[])
  458. {
  459. X    FILE *rc,*rc2,*log,*areas,*mbox,*fw;
  460. X    char home[80],newsrc[80],nrc2[80], templine[255], slog[80];
  461. X    char *nrcline, *list_read;
  462. X    char newsgroup[80],*pos,newsdir[80],ngrp2[80],message[80];
  463. X    char mlist_f[80],mailbox[80];
  464. X    char mailbox_type,area_name[80];
  465. X    int current_area=1, nowrite=0;
  466. X    int i,last,message_cnt;
  467. X    int total_msg=0,message_no;
  468. X    int biggest;
  469. X    int nrcsize = 256, retv;
  470. X    struct dirent *ficdir;
  471. X    DIR *rep;
  472. X    unsigned long offset=0;
  473. #ifdef INFOCOM
  474. X    struct user User;
  475. X
  476. X    strcpy (User.login,getenv("LOGNAME"));
  477. X    if (testuser(&User,USERBASE) >  0)
  478. X    {
  479. X        if ((show_priv_no(3,&User)==0) || show_flag_no(13,&User)) 
  480. X        {
  481. X            /* Not a gold user or has the no getnews flag */
  482. X            fprintf (stderr,"Sorry, you are not allowed to use getnews\n");
  483. X            return (-1);
  484. X        }
  485. X    }
  486. #endif
  487. X    
  488. X    if ((pos=getenv("HOME"))==NULL)
  489. X    {
  490. X        fprintf (stderr,"$HOME not defined\n");
  491. X        return(-1);
  492. X    }
  493. X    strcpy (home,pos);
  494. X
  495. X    read_config();
  496. X
  497. X    if ((argc>1) && (strcmp(argv[1],"-i")==0))
  498. X        Index_only=SET;
  499. X    
  500. X    if (Index_only==SET)
  501. X        Do_index=SET;
  502. X
  503. X    if (Mmdf==SET)
  504. X        mailbox_type='M';
  505. X    else
  506. X        mailbox_type='m';
  507. X
  508. X    if (Compress[0]=='\0') /* unset */
  509. X    {
  510. X        strcpy(Compress,"/usr/local/bin/zip");
  511. X        fprintf(stderr,"WARNING: undefined compression utility, using %s\n",
  512. X            Compress);
  513. X    }
  514. X    /*
  515. X    Opening of Files
  516. X    */
  517. X
  518. X    /* remove the AREAS file */
  519. X    sprintf (templine,"%s/%s",Work_dir,AREALIST);
  520. X    remove(templine);
  521. X
  522. X    sprintf (newsrc,"%s/%s",home,NEWSRC);
  523. X    sprintf (nrc2,"%s/%s",Work_dir,NRC2);
  524. X
  525. X    if((rc=fopen(newsrc,"r"))==NULL)
  526. X    {
  527. X        fprintf (stderr,"File [%s] not found\n",newsrc);
  528. X        return(1);
  529. X    }
  530. X
  531. X    sprintf (slog,"%s/%s",LOGDIR,LOGFILE);
  532. X    log=fopen (slog,"a");
  533. X    if (log==NULL)
  534. X        log=stderr;
  535. X
  536. X    sprintf (mlist_f,"%s/%s",Work_dir,AREALIST);
  537. X    if ((areas=fopen(mlist_f,"w"))==NULL)
  538. X    {
  539. X        fprintf (stderr,"Unable to create [%s] file \n",mlist_f);
  540. X        return(1);
  541. X    }
  542. X
  543. X
  544. X    /*
  545. X    ** Create the name of the first area
  546. X    */
  547. X    sprintf (area_name,"%s/%.3d%s",Work_dir,current_area,NEWSTXT);
  548. X    remove( area_name ); /* just in case */
  549. X    
  550. X    /*
  551. X    ** Processing Mail
  552. X    */
  553. X    message_cnt=0;
  554. X
  555. X    if((Get_mail==ASK) && (Index_only==UNSET))
  556. X    {
  557. X        printf("Do you want to save your mail (y/N) ? ");
  558. X        fflush(stdout);
  559. X        fgets(templine,80,stdin);
  560. X        if ((templine[0]=='y') || (templine[0]=='Y'))
  561. X            Get_mail=SET;
  562. X    }
  563. X
  564. X    if((Get_mail==SET) && (Index_only==UNSET))
  565. X    {
  566. X        if ((pos=getenv("MAIL"))==NULL)
  567. X        {
  568. X            fprintf(stderr,"Error: $MAIL not defined\n");
  569. X            return(1);
  570. X        }
  571. X        strcpy (mailbox,pos);
  572. X        if ((mbox=fopen(mailbox,"r"))!=NULL)
  573. X        {
  574. X            fclose(mbox);
  575. X            add_file(area_name,mailbox,0); /* No rnews header */
  576. X
  577. X            /*
  578. X            ** Update the AREAS file 
  579. X            ** This version does not create an index file 
  580. X            */
  581. X            fprintf (areas,"001\tPrivate Mail\t%cn\n",mailbox_type);
  582. X            message_cnt=0;
  583. X
  584. X            if (Delete_mailbox==UNSET)
  585. X            {
  586. X                /* Move the mailbox to the .oldmail file */
  587. X                sprintf(templine,"%s/.oldmail",home);
  588. X                add_file(templine,mailbox,0);
  589. X                printf("Your mailbox has been appended to file %s\n",templine);
  590. X            }
  591. X            /* Create an empty mailbox */
  592. X            remove(mailbox);
  593. X            fw=fopen(mailbox,"w"); 
  594. X            fclose(fw);
  595. X
  596. X            current_area++;
  597. X            sprintf (area_name,"%s/%.3d%s",Work_dir,current_area,NEWSTXT);
  598. X            remove( area_name ); /* just in case */
  599. X        }
  600. X    }
  601. X
  602. X    /*
  603. X    ** Processing News
  604. X    */
  605. X    if (Mark_read==ASK)
  606. X    {
  607. X        printf("Do you want to mark saved articles as read (y/N) ? ");
  608. X        fflush(stdout);
  609. X        fgets (templine,80,stdin);
  610. X        if ((templine[0]=='y') || (templine[0]=='Y'))
  611. X            Mark_read=SET;
  612. X    }
  613. X
  614. X    if (Mark_read==SET)
  615. X    {
  616. X        /* Create a backup .newsrc */
  617. X        sprintf( templine,"%s/%s.bak", home, NEWSRC);
  618. X        remove( templine );
  619. X
  620. X        add_file( templine, newsrc, 0 );
  621. X
  622. X        /* We create the new .newsrc */
  623. X        if((rc2=fopen(nrc2,"w"))==NULL)
  624. X        {
  625. X            fprintf (stderr,"Unable to create [%s] file\n",nrc2);
  626. X            return(1);
  627. X        }
  628. X    }
  629. X
  630. X    /*
  631. X    ** Main Loop
  632. X    */
  633. X
  634. X    /* 
  635. X    ** For each line in the .newsrc
  636. X    */
  637. X    while( (retv=lfgets(&nrcline,&nrcsize,rc)) == LFGETS_OK ) 
  638. X    {
  639. X        if (Grpmax && (current_area > Grpmax))
  640. X        {
  641. X            if( !nowrite ) /* Prints only the msg once */
  642. X                printf("\nMaximum number of groups reached (%d)\n",Grpmax);
  643. X            nowrite = 1;
  644. X        }
  645. X
  646. X        /* 
  647. X        ** Selects only the subscribed newsgroups 
  648. X        */
  649. X        if (!nowrite && (pos=strchr(nrcline,':'))!=NULL)
  650. X        {
  651. X            if (nrcline[strlen(nrcline)-1]=='\n')
  652. X                nrcline[strlen(nrcline)-1]='\0';
  653. X
  654. X            offset = 0;
  655. X            message_cnt=0; /* reset the message counter */
  656. X            i=0;
  657. X            while (nrcline[i]!=':')
  658. X            {
  659. X                newsgroup[i]=nrcline[i];
  660. X                i++;
  661. X            }
  662. X            newsgroup[i]='\0';
  663. X
  664. X            /*
  665. X            ** Save the list of read articles and
  666. X            ** Get the number of the last one
  667. X            ** the newsrc line looks like :
  668. X            ** groupname: value-value,...,value
  669. X            */
  670. X            pos++;
  671. X            while(*pos==' ') /* Skip the space(s) */
  672. X                pos++;
  673. X            /* 
  674. X            ** pos points to either the first character of the article list,
  675. X            ** or to the \0 string terminator. 
  676. X            */
  677. X            list_read = pos;
  678. X
  679. X            pos=nrcline+strlen(nrcline)-1; /* Points to the latest char */
  680. X            while (isdigit(*pos))
  681. X                pos--;
  682. X            pos++; /* Skip the - , or : character */
  683. X            last=atoi(pos);
  684. X            biggest=last;
  685. X
  686. X            strcpy (ngrp2,newsgroup);
  687. X            dot2slash(newsgroup);
  688. X            sprintf (newsdir,"%s/%s",SPOOL,newsgroup);
  689. X            if (chdir(newsdir)) /* directory doesnt exist */
  690. X            {
  691. X                /*
  692. X                ** This newsgroup does not exist any more
  693. X                ** It may be a good idea to remove it from the .newsrc
  694. X                */
  695. X                fprintf (log,"%s : unknown\n",ngrp2);
  696. X            }
  697. X            else
  698. X            {
  699. X                /* 
  700. X                ** Look for unread file 
  701. X                */
  702. X                if ((rep=opendir(newsdir))==NULL)
  703. X                    fprintf (log,"DIR : %s not readable\n",newsdir);
  704. X                else while ((ficdir=readdir(rep))!=NULL)
  705. X                {
  706. X                    sprintf (message,"%s/%s",newsdir,ficdir->d_name);                
  707. X                    message_no = atoi(ficdir->d_name);
  708. X
  709. X
  710. X                    if (message_no && is_unread(message_no,list_read,last))
  711. X                    {
  712. X                        /*
  713. X                        ** We have found a new article.
  714. X                        ** Look if it's number is bigger than the biggest
  715. X                        */
  716. X                        if (Msgmax && (total_msg >=Msgmax))
  717. X                        {
  718. X                            if( !nowrite )
  719. X                                printf("\nMaximum number of messages reached (%d)\n",Msgmax);
  720. X                            nowrite = 1;
  721. X                        }
  722. X                        
  723. X                        if( !nowrite )
  724. X                        {
  725. X                            if (message_no > biggest)
  726. X                                biggest=message_no;
  727. X                            message_cnt++;
  728. X                            total_msg++;
  729. X                            /* Only display the group if there are messages */
  730. X                            if (message_cnt==1)
  731. X                                printf ("\n%s:",ngrp2);
  732. X
  733. X                            if ((message_cnt%10)==0)
  734. X                            {
  735. X                                printf ("."); /* show the message progression */
  736. X                                fflush(stdout);
  737. X                            }
  738. X                            /*
  739. X                            ** Add the message to the temporary file
  740. X                            ** Or create the index
  741. X                            */
  742. X                            if (Do_index==SET)
  743. X                                index_message(current_area,message,offset);
  744. X                            if (Index_only==UNSET)
  745. X                                offset += add_file (area_name,message,1);    
  746. X
  747. X                        }
  748. X                    }
  749. X                }
  750. X                closedir(rep);
  751. X                if (message_cnt)
  752. X                {
  753. X                    /*
  754. X                    ** Write an entry in the AREAS list file
  755. X                    */
  756. X                    if(get_description(ngrp2,templine)==NULL)
  757. X                        strcpy (templine,"Unknown");
  758. X                    fprintf (areas,"%.3d\t%s\tu%c\t%s\t%d\n",current_area,
  759. X                        ngrp2,
  760. X                        (Do_index==SET) ? 'c' : 'n',
  761. X                        templine,message_cnt);
  762. X                    current_area++;
  763. X                    sprintf (area_name,"%s/%.3d%s",
  764. X                        Work_dir,current_area,NEWSTXT);
  765. X                    remove( area_name ); /* Just in case */
  766. X                }
  767. X                if (Mark_read==SET)
  768. X                {
  769. X                    fprintf (rc2,"%s: 1-%d\n",ngrp2,biggest);
  770. X                }
  771. X            }
  772. X        }
  773. X        else if (Mark_read==SET)
  774. X        {
  775. X            /* Just copy the line as it is */
  776. X            fprintf(rc2,"%s",nrcline);
  777. X        }
  778. X    }
  779. X    if(retv == LFGETS_ERR) 
  780. X    {
  781. X        fprintf(stderr,
  782. X            "\nWarning - Malloc failure while processing file %s\n", NEWSRC );
  783. X        exit(1);
  784. X    }
  785. X
  786. group_done:
  787. X    fclose(rc);
  788. X    if (Mark_read==SET)
  789. X    {
  790. X        fclose(rc2);
  791. X        rc=fopen(newsrc,"w");
  792. X        if (rc!=NULL)
  793. X        {
  794. X            /*
  795. X            ** Rewrites the .newsrc
  796. X            */
  797. X            printf ("\nRewriting .newsrc\n");
  798. X            rc2=fopen(nrc2,"r");
  799. X            while(fgets(nrcline,160,rc2)!=NULL)
  800. X                fprintf(rc,"%s",nrcline);
  801. X            fclose(rc2);
  802. X            fclose(rc);
  803. X            remove(nrc2);
  804. X        }
  805. X        else
  806. X            fprintf (log,"%s : Unable to rewrite .newsrc \n",getenv("LOGNAME"));
  807. X    }
  808. X
  809. X    if (log != stderr)
  810. X        fclose (log);
  811. X    fclose (areas);
  812. X    printf ("\n%d messages processed\n",total_msg);
  813. X
  814. X    /*
  815. X    ** Now compress the work files
  816. X    */
  817. X    chdir(Work_dir);
  818. X
  819. X    /* 
  820. X    ** Check that the compress program exists 
  821. X    ** and that we can create the packet file
  822. X    */
  823. X    sprintf(templine,"%s.%s",Packet_name,Arctype);
  824. X    if (((fw=fopen(Compress,"r"))==NULL)||
  825. X        ((rc=fopen(templine,"w"))==NULL))
  826. X        fprintf(stderr,"Unable to compress *.MSG and AREAS files\n");
  827. X    else
  828. X    {
  829. X        fclose(fw);
  830. X        fclose(rc);
  831. X        remove(templine);
  832. X
  833. X        sprintf (templine,"%s %s.%s *.MSG *.IDX %s",
  834. X            Compress,Packet_name,Arctype,AREALIST);
  835. X        
  836. X        if(system(templine))
  837. X            fprintf(stderr,"Compress program returned an error, work files not removed\
  838. n");
  839. X        else
  840. X        {
  841. X            sprintf (templine,"rm *.MSG *.IDX");
  842. X            system(templine);
  843. X            remove(AREALIST);
  844. X        }
  845. X        printf ("\nFile %s.%s has been created\n",Packet_name,Arctype);
  846. X    }
  847. X    return (0); /* Normal End */
  848. }
  849. X
  850. void dot2slash(line)
  851. char *line;
  852. {
  853. X    if (line==NULL)
  854. X        return;
  855. X    while (*line)
  856. X    {
  857. X        if (*line=='.')
  858. X            *line='/';
  859. X        line++;
  860. X    }
  861. }
  862. X
  863. /* 
  864. ** add_file(f1,f2) append file f2 behind file f1 
  865. ** and return the number of bytes written
  866. */
  867. unsigned long add_file (f1,f2,headermode)
  868. char *f1,*f2;
  869. int headermode;
  870. {
  871. X    char header[80];
  872. X    FILE *df1,*df2;
  873. X    int c;
  874. X    unsigned long length;
  875. X    struct stat buf;
  876. X
  877. X    if ( ((df1=fopen(f1,"a"))==NULL) || ((df2=fopen(f2,"r"))==NULL) )
  878. X    {
  879. X        fprintf (stderr,"Unable to open a file [%s] or [%s]!\n",f1,f2);
  880. X        return (0);
  881. X    }
  882. X
  883. X    if (headermode)
  884. X    {
  885. X        /* Adding a "#! rnews xxxx" line as header */
  886. X        stat(f2,&buf);
  887. X        length=(unsigned long)buf.st_size;
  888. X        sprintf (header,"#! rnews %ld\n",length);
  889. X        length += strlen(header);
  890. X        fprintf (df1,"%s",header);
  891. X    }
  892. X
  893. X    while ((c=fgetc(df2))!=EOF)
  894. X        fputc(c,df1);
  895. X
  896. X    fclose(df1);
  897. X    fclose(df2);
  898. X    return(length);
  899. }
  900. X
  901. /*
  902. ** Get the descrition of the newsgroup
  903. ** or return a null pointer if it cannot be found
  904. */
  905. char *get_description(group,text)
  906. char *group;
  907. char *text;
  908. {
  909. X    char line[255],*pos;
  910. X    int n=strlen(group);
  911. X    FILE *fr;
  912. X    if ((fr=fopen(GROUPS,"r"))==NULL)
  913. X        return(NULL);
  914. X    while (fgets(line,255,fr)!=NULL)
  915. X    {
  916. X        line[strlen(line)-1]='\0';
  917. X        if (strncmp(line,group,n)==0)
  918. X        {
  919. X            pos=line+n; /* Points to the tab */
  920. X            if ((*pos=='\0')||(*(pos+1)=='\0'))
  921. X                return(NULL);
  922. X            while ((*pos=='\t')||(*pos==' '))
  923. X                pos++;
  924. X            strcpy (text,pos);
  925. X            return(text);
  926. X        }
  927. X    }
  928. X    fclose( fr );
  929. X    return(NULL);
  930. }
  931. X
  932. /*
  933. ** Return 1 if the article of number message_no is either greater than the
  934. ** last read or not in the list of read articles
  935. */
  936. #ifdef __STDC__
  937. int is_unread(int message_no, char *list_read, int last)
  938. #else
  939. int is_unread(message_no,list_read,last)
  940. int message_no,last;
  941. char *list_read;
  942. #endif
  943. {
  944. X    int begin,end,value;
  945. X    char orig, *pos1, *pos;
  946. X    if ((message_no > last) || (list_read[0]=='\0'))
  947. X        return(1);
  948. X
  949. X    pos=list_read;
  950. X    orig = 0;
  951. X
  952. X    while (*pos) {
  953. X        /* Read the first number */
  954. X        pos1=pos;
  955. X        while (isdigit(*pos))
  956. X            pos++;
  957. X        switch(*pos) {
  958. X            case ',': /* A single number */
  959. X            case '\0': /* End of string */
  960. X                orig = *pos;
  961. X                value=atoi(pos1);
  962. X                if (message_no == value)
  963. X                    return(0); /* This article has been read */
  964. X                if (message_no < value)
  965. X                    return(1); /* Lower than the lowest read */
  966. X                break;
  967. X
  968. X            case '-': /* A range */
  969. X                begin = atoi(pos1);
  970. X                if (message_no == begin)
  971. X                    return(0); /* This article has been read */
  972. X                if (message_no < begin)
  973. X                    return(1); /* Lower than the lowest read */
  974. X                /* Read the second number */
  975. X                pos++;
  976. X                pos1=pos;
  977. X                while(isdigit(*pos))
  978. X                    pos++;
  979. X                orig = *pos;
  980. X                end = atoi(pos1);
  981. X                if (message_no < begin)
  982. X                    return(1);
  983. X                if (message_no <= end)
  984. X                    return(0);
  985. X                break;
  986. X
  987. X
  988. X            default : /* Unknown char */
  989. X                orig='1';
  990. X                fprintf(stderr,"Warning, char <%c> unrecognised in .newsrc\n",*pos);
  991. X                break;
  992. X        }
  993. X        if (orig)
  994. X            pos++;
  995. X    }
  996. X    return(1); /* Unread */
  997. }
  998. X
  999. X
  1000. char *upperit(line)
  1001. char *line;
  1002. {
  1003. X    char *pos=line;
  1004. X    while (*pos)
  1005. X    {
  1006. X        *pos=toupper(*pos);
  1007. X        pos++;
  1008. X    }
  1009. X    return (line);
  1010. }
  1011. X
  1012. X
  1013. /* 
  1014. ** Get a token from the token list out of the line
  1015. ** update pos as the position in the line after the token
  1016. ** and return the token number if found, -1 else.
  1017. */
  1018. #ifdef __STDC__
  1019. int get_token(char *line,char **tlist,char **pos)
  1020. #else
  1021. int get_token(line,tlist,pos)
  1022. char *line, **tlist,**pos;
  1023. #endif
  1024. {
  1025. X    int i=0,l,ll;
  1026. X    char *c;
  1027. X
  1028. X    /* search for the "=" separator */
  1029. X    c=strchr(line,'=');
  1030. X    if (c==NULL)
  1031. X        return (-1); 
  1032. X    ll=c-line; /* Get line length */
  1033. X    *c='\0';
  1034. X    /* *pos points to the first non blank character after the = */
  1035. X    *pos=c+1; 
  1036. X    while ((**pos==' ')||(**pos=='\t'))
  1037. X        *pos += 1;
  1038. X    upperit(line);
  1039. X    while (tlist[i][0])
  1040. X    {
  1041. X        l=strlen(tlist[i]);
  1042. X        if((l==ll) && (strcmp(line,tlist[i])==0))
  1043. X            return(i);
  1044. X        i++;
  1045. X    }
  1046. X    return(-1); /* failure */
  1047. }
  1048. X
  1049. /*
  1050. ** Open the .getnewsrc file and read the config 
  1051. */
  1052. void read_config()
  1053. {
  1054. X    FILE *fr;
  1055. X    int n;
  1056. X    char line[80],old_line[80],*pos,rcfile[80];
  1057. X    static char *tlist[15]={
  1058. X        "MSGMAX",
  1059. X        "GRPMAX",
  1060. X        "MMDF",
  1061. X        "USENET_ONLY",
  1062. X        "MAIL_ONLY",
  1063. X        "DELETE_MAILBOX",
  1064. X        "GET_MAIL",
  1065. X        "MARK_READ",
  1066. X        "COMPRESS",
  1067. X        "PACKET_NAME",
  1068. X        "WORK_DIR",
  1069. X        "ARCTYPE",
  1070. X        "DO_INDEX",
  1071. X        "INDEX_ONLY",
  1072. X        ""};
  1073. X
  1074. X
  1075. X    /* Default */
  1076. X
  1077. X    /* 
  1078. X    ** The maximum number of articles and of newsgroups
  1079. X    ** If UNSET, no limit
  1080. X    */
  1081. X
  1082. X    Grpmax = Msgmax = UNSET; 
  1083. X
  1084. X    /*
  1085. X    ** The following fields accept values SET and UNSET
  1086. X    */
  1087. X    Mmdf = Usenet_only = Mail_only = Delete_mailbox = Index_only = UNSET;
  1088. X    Do_index = SET;
  1089. X
  1090. X    /*
  1091. X    ** The following field accept values SET, UNSET and ASK
  1092. X    */
  1093. X    Get_mail = Mark_read = ASK;
  1094. X
  1095. X    Compress[0]='\0';
  1096. X    strcpy(Arctype,"zip");
  1097. X    strcpy(Packet_name,"INFONEWS");
  1098. X    sprintf(Work_dir,"%s/News",getenv("HOME"));
  1099. X
  1100. X    sprintf(rcfile,"%s/.getnewsrc",getenv("HOME"));
  1101. X    if ((fr=fopen(rcfile,"r"))==NULL)
  1102. X        return; /* No config file, use default values */
  1103. X
  1104. X    while( fgets( line, 80, fr ) != NULL )
  1105. X    {
  1106. X        strcpy( old_line, line );
  1107. X
  1108. X        /* Ignore comments and blank lines */
  1109. X        if( line[0] != '#' && line[0] != '\n' ) 
  1110. X        {
  1111. X            if (line[strlen(line)-1]=='\n') /* Remove end CR */
  1112. X                line[strlen(line)-1]='\0';
  1113. X
  1114. X            switch (get_token(line,tlist,&pos))
  1115. X            {
  1116. X                case 0: /* msgmax */
  1117. X                    Msgmax = atoi(pos);
  1118. X                    break;
  1119. X                
  1120. X                case 1: /* grpmax */
  1121. X                    Grpmax = atoi(pos);
  1122. X                    break;
  1123. X
  1124. X                case 2: /* mmdf */
  1125. X                    if( (n = su_get( old_line, pos )) != -1 )
  1126. X                        Mmdf = n;
  1127. X                    break;
  1128. X
  1129. X                case 3: /* Usenet Only */
  1130. X                    if( (n = su_get( old_line, pos )) != -1 )
  1131. X                        Usenet_only = n;
  1132. X                    break;
  1133. X
  1134. X                case 4: /* Mail Only */
  1135. X                    if( (n = su_get( old_line, pos )) != -1 )
  1136. X                        Mail_only = n;
  1137. X                    break;
  1138. X
  1139. X                case 5: /* Delete Mailbox */
  1140. X                    if( (n = sua_get( old_line, pos )) != -1 )
  1141. X                        Delete_mailbox = n;
  1142. X                    break;
  1143. X
  1144. X                case 6: /* Get Mail */
  1145. X                    if( (n = sua_get( old_line, pos )) != -1 )
  1146. X                        Get_mail = n;
  1147. X                    break;
  1148. X
  1149. X                case 7: /* Mark Read */
  1150. X                    if( (n = sua_get( old_line, pos )) != -1 )
  1151. X                        Mark_read = n;
  1152. X                    break;
  1153. X
  1154. X                case 8: /* Compress */
  1155. X                    exp_env( strcpy(Compress,pos) );
  1156. X                    break;
  1157. X
  1158. X                case 9: /* Packet Name */
  1159. X                    exp_env( strcpy(Packet_name,pos) );
  1160. X                    break;
  1161. X
  1162. X                case 10: /* Work dir */
  1163. X                    exp_env( strcpy(Work_dir,pos) );
  1164. X                    break;
  1165. X
  1166. X                case 11: /* Arc type */
  1167. X                    exp_env( strcpy(Arctype,pos) );
  1168. X                    break;
  1169. X
  1170. X                case 12: /* Get index */
  1171. X                    if( (n = su_get( old_line, pos )) != -1 )
  1172. X                        Do_index = n;
  1173. X                    break;
  1174. X
  1175. X                case 13: /* Get index */
  1176. X                    if( (n = su_get( old_line, pos )) != -1 )
  1177. X                        Index_only = n;
  1178. X                    break;
  1179. X
  1180. X                default:
  1181. X                    fprintf(stderr,"Line <%s> has no known keyword\n",old_line);
  1182. X                    break;
  1183. X            }
  1184. X        }
  1185. X    }
  1186. X    fclose(fr);
  1187. }
  1188. X
  1189. int su_get(line,pos)
  1190. char *line;
  1191. char *pos;
  1192. {
  1193. X    switch( *pos ) 
  1194. X    {
  1195. X        case 'Y':
  1196. X        case 'y':
  1197. X        case 'S':
  1198. X        case 's':
  1199. X            return(SET);
  1200. X
  1201. X        case 'N':
  1202. X        case 'n':
  1203. X        case 'U':
  1204. X        case 'u':
  1205. X            return(UNSET);
  1206. X
  1207. X        default:
  1208. X            fprintf(stderr, "Error in config file: Line <%s> ",line);
  1209. X            fprintf(stderr, "should be either SET or UNSET\n");
  1210. X            break;
  1211. X    }
  1212. X    return( -1 );
  1213. }
  1214. X
  1215. int sua_get(line,pos)
  1216. char *line;
  1217. char *pos;
  1218. {
  1219. X    switch( *pos ) 
  1220. X    {
  1221. X        case 'Y':
  1222. X        case 'y':
  1223. X        case 'S':
  1224. X        case 's':
  1225. X            return(SET);
  1226. X
  1227. X        case 'N':
  1228. X        case 'n':
  1229. X        case 'U':
  1230. X        case 'u':
  1231. X            return(UNSET);
  1232. X
  1233. X        case 'A':
  1234. X        case 'a':
  1235. X            return(ASK);
  1236. X
  1237. X        default:
  1238. X            fprintf(stderr, "Error in config file: Line <%s> ",line);
  1239. X            fprintf(stderr, "should be either SET, UNSET, or ASK\n");
  1240. X            break;
  1241. X    }
  1242. X    return( -1 );
  1243. }
  1244. X
  1245. void index_message(area,message,offset)
  1246. int area;
  1247. char *message;
  1248. unsigned long offset;
  1249. {
  1250. X    char From[80],Subject[80],Date[80],temp[80],line[512],Ref[80],Id[80],*pos;
  1251. X    int bytes=0,line_no=0,headermode=1;
  1252. X    FILE *fr,*fw;
  1253. X    struct stat buf;
  1254. X
  1255. X    From[0] = Subject[0] = Date[0] = Ref[0] = '\0';
  1256. X
  1257. X    sprintf(temp,"%s/%.3d.IDX",Work_dir,area);
  1258. X
  1259. X    if ( ((fw=fopen(temp,"a"))==NULL) || ((fr=fopen(message,"r"))==NULL) )
  1260. X    {
  1261. X        fprintf (stderr,"Unable to open a file [%s] or [%s]!\n",temp,message);
  1262. X        return;
  1263. X    }
  1264. X
  1265. X    /* Adding a the size of "#! rnews xxxx" line to the offset */
  1266. X    stat( message, &buf );
  1267. X    sprintf( temp, "#! rnews %ld\n", (unsigned long)buf.st_size);
  1268. X    offset += strlen( temp );
  1269. X
  1270. X    /* Find the last part of the path for the mesg Id */
  1271. X    pos=strrchr(message,'/');
  1272. X    if (pos==NULL)
  1273. X        strcpy(Id,message);
  1274. X    else
  1275. X        strcpy(Id,pos+1);
  1276. X
  1277. X    while(fgets(line,512,fr)!=NULL)
  1278. X    {
  1279. X        line[511]='\0'; /* Just in case */
  1280. X        if (line[strlen(line)-1]=='\n')
  1281. X            line[strlen(line)-1]='\0';
  1282. X        if (headermode)
  1283. X        {
  1284. X            if (line[0]=='\0')
  1285. X                headermode=0;
  1286. X            else
  1287. X            {
  1288. X                if (strncmp(line,"From: ",6)==0)
  1289. X                    strcpy(From,line+6);
  1290. X                else if (strncmp(line,"Subject: ",9)==0)
  1291. X                    strcpy(Subject,line+9);
  1292. X                else if (strncmp(line,"Date: ",6)==0)
  1293. X                    strcpy(Date,line+6);
  1294. X                else if (strncmp(line,"References: ",12)==0)
  1295. X                    strcpy(Ref,line+12);
  1296. X            }
  1297. X        }
  1298. X        else
  1299. X            line_no++;
  1300. X        bytes += strlen(line);
  1301. X    }
  1302. X    fprintf(fw,"%ld\t%s\t%s\t%s\t%s\t%s\t%d\t%d\n",offset,
  1303. X        Subject,From,Date,Id,Ref,bytes,line_no);
  1304. X    fclose(fr);
  1305. X    fclose(fw);
  1306. }
  1307. X
  1308. /*
  1309. **      exp_env()
  1310. **
  1311. ** Expand any environment variables in input string.
  1312. ** Put result back into input string.
  1313. ** Input string must be big enough to hold the expanded expression.
  1314. **
  1315. ** Returns 0 (FALSE) if any specified environment variables are not defined;
  1316. ** Else returns 1 (TRUE).
  1317. */
  1318. #ifdef __STDC__
  1319. int exp_env(char *s)
  1320. #else
  1321. int exp_env(s)
  1322. char *s;
  1323. #endif
  1324. {
  1325. X    char *in, *out, *cptr, *env_val;
  1326. X    int c, cv, ret_val;
  1327. X    char env_name[30];
  1328. X    char *temp;
  1329. X
  1330. X    if(strchr(s,'$') == NULL)
  1331. X        return(1);
  1332. X
  1333. X    temp = (char *)malloc((unsigned)(strlen(s)+1));
  1334. X    if(temp == NULL) 
  1335. X        {
  1336. X        fprintf(stderr, "Error - function exp_env: Malloc failed.\n");
  1337. X        return(0);
  1338. X    }
  1339. X
  1340. X    strcpy(temp,s);
  1341. X    in = temp;
  1342. X    out = s;
  1343. X    ret_val = 1;
  1344. X
  1345. X    while( c=*in++) 
  1346. X        {    /* While thare are characters */
  1347. X        if(c != '$') 
  1348. X            {
  1349. X            /* regular part of string */
  1350. X            *out++ = (char)c;
  1351. X        }
  1352. X        else 
  1353. X            {
  1354. X            /* Beginning of environment variable */
  1355. X            /* Pick off the name of environment variable */
  1356. X            cptr = env_name;
  1357. X            while( (c=*in++) && ( isalnum(c) || c == '_') )
  1358. X                *cptr++ = (char)c;
  1359. X            *cptr = '\0';
  1360. X            in--;
  1361. X            /* Get value */
  1362. X            env_val = getenv(env_name);
  1363. X            if(env_val == NULL)
  1364. X                ret_val = 0;
  1365. X            else 
  1366. X                {
  1367. X                /* copy value into output string */
  1368. X                cptr = env_val;
  1369. X                while(cv=*cptr++)
  1370. X                    *out++ = (char)cv;
  1371. X            }
  1372. X            if(c == '\0') break;  /* End of input string */
  1373. X        }
  1374. X    }
  1375. X
  1376. X    *out = '\0'; /* Terminate resulting string. */
  1377. X
  1378. X    free((char *)temp);  /* Release malloced space */
  1379. X
  1380. X    return(ret_val);
  1381. }
  1382. X
  1383. /*
  1384. **  Function:
  1385. **
  1386. **       int lfgets(char *s, int *ns, FILE *stream)
  1387. **
  1388. **  Gets an arbitrarily-long line from an input stream. The terminating
  1389. **  newline is returned also.
  1390. **
  1391. **  If s is NULL, then lfgets uses malloc() to get storage space of size ns
  1392. **  or larger to hold the input line. A pointer to the newly-malloced
  1393. **  space is returned in parameter s.
  1394. **  If s is not NULL, it must be a pointer obtained from a malloc-like
  1395. **  function (malloc, calloc, realloc, etc.).
  1396. **
  1397. **  Lfgets starts filling s with the input line.
  1398. **  If the line is longer than s, then lfgets uses realloc() as necessary
  1399. **  to get a large enough storage space. In this case, pointer s is changed
  1400. **  to point to the (possibly-relocated) new storage area,
  1401. **  and ns will change to reflect the new size of the storage space.
  1402. **
  1403. **  If all goes well, lfgets returns LFGETS_OK.
  1404. **  If the first character read is an end-of-file, lfgets returns LFGETS_EOF.
  1405. **  If malloc() or realloc() fail, then lfgets LFGETS_ERR.
  1406. */
  1407. X
  1408. #ifdef __STDC__
  1409. int lfgets(char **s, int *ns, FILE *stream)
  1410. #else
  1411. int lfgets(s, ns, stream)
  1412. char **s;
  1413. int *ns;
  1414. FILE *stream;
  1415. #endif
  1416. {
  1417. X    int c, i;
  1418. X    int maxch;
  1419. X
  1420. X    if(*s == NULL) {
  1421. X        /* malloc some space to start with */
  1422. X        *ns = 256;
  1423. X        *s = (char *)malloc((unsigned)*ns);
  1424. X        if(*s == (char *)NULL)
  1425. X            return(LFGETS_ERR);
  1426. X    }
  1427. X
  1428. X    i = 0;
  1429. X
  1430. X    while(1) {
  1431. X        maxch = *ns - 1;  /* maximum # of characters to read into array,
  1432. X                             not counting the terminating null. */
  1433. X
  1434. X
  1435. X        /* Read data, putting it into s. */
  1436. X        for(; i < maxch; i++) {
  1437. X            c = fgetc(stream);
  1438. X
  1439. X            if(c == EOF) {
  1440. X                if(i == 0)
  1441. X                    /* EOF at first attempt to read */
  1442. X                    return(LFGETS_EOF);
  1443. X                else {
  1444. X                    /* last line of file had no \n terminator. */
  1445. X                    (*s)[i+1] = '\0';  /* terminate string. */
  1446. X                    return(LFGETS_OK);
  1447. X                }
  1448. X            }
  1449. X
  1450. X            (*s)[i] = (char)c;
  1451. X            if(c == '\n') {
  1452. X                /* we have found the end of the input line */
  1453. X                (*s)[++i] = '\0';  /* terminate string. */
  1454. X                return(LFGETS_OK);
  1455. X            }
  1456. X        }
  1457. X
  1458. X        /* There is more of the line yet to read */
  1459. X        /* Get more storage space. */
  1460. X        *ns += 256;
  1461. X        *s = (char *)realloc(*s, (unsigned)*ns);
  1462. X        if(*s == (char *)NULL)
  1463. X            return(LFGETS_ERR);
  1464. X
  1465. X        /* And, repeat. */
  1466. X    }
  1467. X
  1468. }
  1469. X
  1470. SHAR_EOF
  1471. chmod 0440 slnr/getnews.c ||
  1472. echo 'restore of slnr/getnews.c failed'
  1473. Wc_c="`wc -c < 'slnr/getnews.c'`"
  1474. test 24574 -eq "$Wc_c" ||
  1475.     echo 'slnr/getnews.c: original size 24574, current size' "$Wc_c"
  1476. rm -f _shar_wnt_.tmp
  1477. fi
  1478. # ============= slnr/postreply.c ==============
  1479. if test -f 'slnr/postreply.c' -a X"$1" != X"-c"; then
  1480.     echo 'x - skipping slnr/postreply.c (File already exists)'
  1481.     rm -f _shar_wnt_.tmp
  1482. else
  1483. > _shar_wnt_.tmp
  1484. echo 'x - extracting slnr/postreply.c (Text)'
  1485. sed 's/^X//' << 'SHAR_EOF' > 'slnr/postreply.c' &&
  1486. /*
  1487. ** Postreply.c : Posting mail and messages from SLNP reply packet
  1488. ** Author      : Philippe Goujard
  1489. ** Started     : 08/04/93
  1490. ** Version     : 1.3
  1491. */
  1492. X
  1493. #include <stdio.h>
  1494. #include <string.h>
  1495. /* Post article with partial header */
  1496. #define INEWSCMD "/usr/lib/news/inews -h" 
  1497. #define MAILCMD "/usr/ucblib/sendmail -t < "
  1498. #define TMP "/usr/tmp"
  1499. #define MMDF_SEPARATOR ""
  1500. #define MAIL_SEPARATOR "From "
  1501. X
  1502. union converter
  1503. {
  1504. X    unsigned long l;
  1505. X    unsigned char c[4];
  1506. } Conv;
  1507. X
  1508. int is_big_endian()
  1509. {
  1510. X    char testline[80];
  1511. X
  1512. X    Conv.l=16909060; /* Should be 01 02 03 04 */
  1513. X    sprintf( testline, "%d%d%d%d",Conv.c[0],Conv.c[1],Conv.c[2],Conv.c[3]);
  1514. X    if( strcmp( testline, "1234" ) == 0 )
  1515. X        return( 1 ); /* true */
  1516. X    return( 0 );
  1517. }
  1518. X
  1519. void post_new_articles(msg_file, encoding, program )
  1520. char *msg_file, *program;
  1521. char encoding;
  1522. {
  1523. X    FILE *fr,*fw;
  1524. X    char c, *ptr, line[255],line2[255], tmpname[80];
  1525. X
  1526. X    if ((fr=fopen(msg_file,"r"))==NULL)
  1527. X        return; /* No article to post */
  1528. X
  1529. X    sprintf(tmpname,"%s/art.%d",TMP,getpid());
  1530. X    if ((fw=fopen(tmpname,"w"))==NULL)
  1531. X    {
  1532. X        fclose(fr);
  1533. X        return;
  1534. X    }
  1535. X    switch( encoding )
  1536. X    {
  1537. X        case 'm': /* Mail format */
  1538. X            fgets(line,255,fr); /* Get the From line */
  1539. X            fprintf(fw,"%s",line);
  1540. X
  1541. X            while (fgets(line,255,fr)!=NULL)
  1542. X            {
  1543. X                if ( strncmp( line, "From ", 5)==0)
  1544. X                {
  1545. X                    /* Process the article */
  1546. X                    fclose(fw);
  1547. X                    sprintf( line2, "%s %s", program, tmpname);
  1548. X                    system( line2 );
  1549. X                    fw=fopen(tmpname,"w"); /* Create a new tmp file for next article */
  1550. X                    fprintf(fw,"%s",line);
  1551. X                }
  1552. X                else
  1553. X                    fprintf(fw,"%s",line);
  1554. X            }
  1555. X            /* Process the last article */
  1556. X            fclose(fw);
  1557. X            sprintf (line,"%s %s",program,tmpname);
  1558. X            system(line);
  1559. X            break;
  1560. X
  1561. X        case 'M': /* MMDF format */
  1562. X            fgets(line,255,fr); /* Get the CtrlAs line */
  1563. X
  1564. X            while (fgets(line,255,fr)!=NULL)
  1565. X            {
  1566. X                if ( strncmp( line, MMDF_SEPARATOR, 4)==0)
  1567. X                {
  1568. X                    /* Process the article */
  1569. X                    fclose(fw);
  1570. X                    sprintf( line2, "%s %s", program, tmpname);
  1571. X                    system( line2 );
  1572. X                    fw=fopen(tmpname,"w"); /* Create a new tmp file for next article */
  1573. X                    fgets(line,255,fr); /* Get the CtrlAs line */
  1574. X                }
  1575. X                else
  1576. X                    fprintf(fw,"%s",line);
  1577. X            }
  1578. X            fclose(fw);
  1579. X            break;
  1580. X
  1581. X        case 'u':
  1582. X            /* Get the rnews line */
  1583. X            fgets(line,255,fr);
  1584. X
  1585. X            while (fgets(line,255,fr)!=NULL)
  1586. X            {
  1587. X                if (strncmp(line,"#! rnews ",9)==0)
  1588. X                {
  1589. X                    /* Process the article */
  1590. X                    fclose(fw);
  1591. X                    sprintf (line,"%s %s",program,tmpname);
  1592. X                    system(line);
  1593. X                    fw=fopen(tmpname,"w"); /* Create a new tmp file for next article */
  1594. X                }
  1595. X                else
  1596. X                    fprintf(fw,"%s",line);
  1597. X            }
  1598. X            /* Process the last article */
  1599. X            fclose(fw);
  1600. X            sprintf (line,"%s %s",program,tmpname);
  1601. X            system(line);
  1602. X            break;
  1603. X
  1604. X        case 'b':
  1605. X        case 'B':
  1606. X            while( (c=fgetc( fr )) != EOF )
  1607. X            {
  1608. X                if( is_big_endian() ) /* Sparc and 68k processors */
  1609. X                {
  1610. X                    Conv.c[0] = c;
  1611. X                    Conv.c[1] = fgetc(fr);
  1612. X                    Conv.c[2] = fgetc(fr);
  1613. X                    Conv.c[3] = fgetc(fr);
  1614. X                }
  1615. X                else /* Intel processors */
  1616. X                {
  1617. X                    Conv.c[3] = c;
  1618. X                    Conv.c[2] = fgetc(fr);
  1619. X                    Conv.c[1] = fgetc(fr);
  1620. X                    Conv.c[0] = fgetc(fr);
  1621. X                }
  1622. X                /* Allocate memory */
  1623. X                if( ( ptr = (char *)malloc( Conv.l * sizeof( char * ) ) ) == NULL )
  1624. X                {
  1625. X                    fclose( fr );
  1626. X                    fclose( fw );
  1627. X                    remove(tmpname);
  1628. X                    return;
  1629. X                }
  1630. X
  1631. X                fread( ptr, 1, Conv.l, fr );
  1632. X                fwrite( ptr, 1, Conv.l, fw );
  1633. X                /* Process the article */
  1634. X                fclose(fw);
  1635. X                sprintf (line,"%s %s",program,tmpname);
  1636. X                system(line);
  1637. X                fw=fopen(tmpname,"w"); /* Create a new tmp file for next article */
  1638. X                free( ptr );
  1639. X            }
  1640. X            fclose(fw);
  1641. X            break;
  1642. X
  1643. X    }
  1644. X    fclose(fr);
  1645. X /*    remove(tmpname); */
  1646. }
  1647. X
  1648. main()
  1649. {
  1650. X    FILE *fr;
  1651. X    int ln=0;
  1652. X    char line[80],*p,message[20],program[80];
  1653. X
  1654. X    if ((fr=fopen("REPLIES","r"))==NULL)
  1655. X    {
  1656. X        fprintf(stderr,"Nothing to post\n");
  1657. X        return;
  1658. X    }
  1659. X    while(fgets(line,80,fr)!=NULL)
  1660. X    {
  1661. X        ln++;
  1662. X        if ((p=strchr(line,'\t'))==NULL)
  1663. X        {
  1664. X            fprintf(stderr,"Error in REPLIES, no prefix in line %d\n",ln);
  1665. X            return;
  1666. X        }
  1667. X        *p='\0';
  1668. X        sprintf(message,"%s.MSG",line);
  1669. X        strcpy(line,p+1);
  1670. X        if ((p=strchr(line,'\t'))==NULL)
  1671. X        {
  1672. X            fprintf(stderr,"Error in REPLIES no reply kind in line %d\n",ln);
  1673. X            return;
  1674. X        }
  1675. X        *p='\0';
  1676. X        p++; /* Get the encoding type */
  1677. X        if (strcmp(line,"mail")==0)
  1678. X            strcpy( program, MAILCMD );
  1679. X        else if (strcmp(line,"news")==0)
  1680. X            strcpy( program, INEWSCMD );
  1681. X        else
  1682. X        {
  1683. X            fprintf(stderr,"Error : reply kind invalid in line %d\n",ln);
  1684. X            return;
  1685. X        }
  1686. X        post_new_articles(message, *p, program);
  1687. X    }
  1688. X    fclose(fr);
  1689. }
  1690. SHAR_EOF
  1691. chmod 0440 slnr/postreply.c ||
  1692. echo 'restore of slnr/postreply.c failed'
  1693. Wc_c="`wc -c < 'slnr/postreply.c'`"
  1694. test 4409 -eq "$Wc_c" ||
  1695.     echo 'slnr/postreply.c: original size 4409, current size' "$Wc_c"
  1696. rm -f _shar_wnt_.tmp
  1697. fi
  1698. # ============= slnr/sig.txt ==============
  1699. if test -f 'slnr/sig.txt' -a X"$1" != X"-c"; then
  1700.     echo 'x - skipping slnr/sig.txt (File already exists)'
  1701.     rm -f _shar_wnt_.tmp
  1702. else
  1703. > _shar_wnt_.tmp
  1704. echo 'x - extracting slnr/sig.txt (Text)'
  1705. sed 's/^X//' << 'SHAR_EOF' > 'slnr/sig.txt' &&
  1706. The one and only usenet god : Email god@heaven.com
  1707. SHAR_EOF
  1708. chmod 0440 slnr/sig.txt ||
  1709. echo 'restore of slnr/sig.txt failed'
  1710. Wc_c="`wc -c < 'slnr/sig.txt'`"
  1711. test 51 -eq "$Wc_c" ||
  1712.     echo 'slnr/sig.txt: original size 51, current size' "$Wc_c"
  1713. rm -f _shar_wnt_.tmp
  1714. fi
  1715. # ============= slnr/slnp.fmt ==============
  1716. if test -f 'slnr/slnp.fmt' -a X"$1" != X"-c"; then
  1717.     echo 'x - skipping slnr/slnp.fmt (File already exists)'
  1718.     rm -f _shar_wnt_.tmp
  1719. else
  1720. > _shar_wnt_.tmp
  1721. echo 'x - extracting slnr/slnp.fmt (Text)'
  1722. sed 's/^X//' << 'SHAR_EOF' > 'slnr/slnp.fmt' &&
  1723. X
  1724. X                         SLNP file format
  1725. X                         ~~~~~~~~~~~~~~~~
  1726. X
  1727. Author  : Philippe Goujard (author of SLNR)
  1728. X
  1729. Date    : 24 Apr 1993
  1730. X
  1731. Version : 1.1 Draft
  1732. X
  1733. X
  1734. X
  1735. X
  1736. X
  1737. X
  1738. X
  1739. X
  1740. X
  1741. X
  1742. Mail me at <pgoujard@infocom.co.uk> for the latest version of this format
  1743. X
  1744. The author of this original document may be contacted via e-mail at
  1745. rhys@cs.uq.oz.au.
  1746. X
  1747. X
  1748. X
  1749. X
  1750. X
  1751. 0. Document Control
  1752. ===================
  1753. X
  1754. 0.1 Contents List
  1755. ~~~~~~~~~~~~~~~~~
  1756. X
  1757. <To be provided >
  1758. X
  1759. X
  1760. 0.2 Document Cross Reference
  1761. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1762. X
  1763. [1] : RFC 822, Standard for the format of Arpa Internet text messages (1982)
  1764. X
  1765. [2] : RFC 1036
  1766. X
  1767. [3] : RFC 1341
  1768. X
  1769. [4] : The Helldiver Packet Format version 1.1 by Rhys Weatherley.
  1770. X
  1771. X
  1772. 0.3 Copyright notice :
  1773. ~~~~~~~~~~~~~~~~~~~~~~
  1774. This document is in the public domain : you can copy it, use it to make 
  1775. off-line readers or on-line "doors" on bbs and servers and even make money
  1776. out of it. The ONLY restriction being that when you copy or distribute that
  1777. document you copy this notice so other people will have the same rights
  1778. as you.
  1779. X
  1780. [4] is Copyright (c) 1992 Rhys Weatherley
  1781. X
  1782. 0.4 Changes Forecast
  1783. ~~~~~~~~~~~~~~~~~~~~
  1784. X
  1785. - The COMMAND file will have to be defined, and specially what command are
  1786. allowed.
  1787. X
  1788. - Optionals files and fields can become mandatory in future versions.
  1789. X
  1790. X
  1791. 0.5 Changes from the previous issue
  1792. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1793. X
  1794. Almost everything. 
  1795. SLNP Version 1.0 was a beta release and was intended to change after receiving
  1796. the comments from testers.
  1797. This version is mostly equivalent to [4].
  1798. X
  1799. Main changes with SLNP v1.0 are:
  1800. X
  1801. X   - The file names have changed and the text of the newsgroups are now
  1802. X   splitted into different files.
  1803. X
  1804. X   - There are new files to Index and display Info
  1805. X
  1806. X   - The field separator is no longer a ":" but a Tabulation
  1807. X
  1808. X   - The format of the messages include a "#! rnews size" line at the top
  1809. X   of each message but no longer include the "***[END]***" as message
  1810. X   separator.
  1811. X
  1812. X
  1813. X
  1814. X
  1815. 1. General
  1816. ==========
  1817. X
  1818. X
  1819. 1.1 Scope
  1820. ~~~~~~~~~
  1821. X
  1822. This document provides a design for an off-line news readers packet format
  1823. compatible with [4].
  1824. X
  1825. X
  1826. 1.2) Introduction
  1827. ~~~~~~~~~~~~~~~~~
  1828. X
  1829. For many years, the FidoNet community has been using QWK and other formats
  1830. to enable users to download their mail and conferences to be read while
  1831. off-line.  This not only saves phone charges and prevents tying up BBS
  1832. lines for long periods of time; it also allows a user to use much more
  1833. powerful tools on their own machine to process the downloaded "packets"
  1834. than what can be made available in an on-line environment.
  1835. X
  1836. To date however, very little work has been done in the USENET and dial-in
  1837. Unix community to facilitate the same user operations.  Some attempts have
  1838. been made to use QWK, but due to QWK's limitations and unsuitability for
  1839. the USENET message formats, such efforts have not been very successful.
  1840. X
  1841. Within USENET, the tendency seems to be either "dial-in to some other
  1842. machine and put up with it", or "set up your own USENET site".  The former
  1843. keeps the user at the mercy of whatever user interfaces the admin of the
  1844. other machine sees fit to install, and the latter requires far more
  1845. computing knowledge than the average computer user is expected to have.
  1846. Both of these can serve to lock out large portions of the computer-literate
  1847. public from experiencing USENET.  The latter option can also give rise to
  1848. security problems in the form of forged USENET messages, which a more
  1849. controlled dial-in system avoids.
  1850. X
  1851. The purpose of this document is to define a new packet format which is
  1852. aware of the conventions used in the USENET community, forming a middle
  1853. ground between dial-in user interfaces and full USENET connectivity.  It is
  1854. not limited to downloading USENET news however.  The same format could be
  1855. used to enable a Unix user to package up their Unix mailbox and download it
  1856. for later perusal.  The format is extensible to other kinds of news or
  1857. conference systems, so it is feasible, although not yet defined, that QWK
  1858. or FidoNet messages could be accomodated within the same packet as USENET
  1859. messages.
  1860. X
  1861. X
  1862. X
  1863. 1.3) Vocabulary and naming convention
  1864. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1865. X - SLNR : Silly Little News Reader : One of the newsreaders that can read
  1866. X   SLNP packets.
  1867. X
  1868. X - SLNP : The packet file transmitted between the host and the home machine
  1869. X   However, by extension we often use "slnr" when refering to the packet. 
  1870. X   This is improper : SLNR is ONE of the programs that can read SLNP packets 
  1871. X   but it will not be the only one.
  1872. X
  1873. X - Message area : A public conference, known in the usenet community as
  1874. X   "newsgroup" and in the CompuServe community as "Forum".
  1875. X
  1876. X - Host or generating host : The machine on which the packet is created.
  1877. X
  1878. X - Receiving host or home machine : The machine on which the packet will
  1879. X   be read.
  1880. X
  1881. X - Packet Generator : The program, run on the host, which creates a packet
  1882. X   in the SLNP format.
  1883. X
  1884. X - Packet poster   : Th program, run on the hosts, which extract the
  1885. X   replies from an uploaded packet and post them "to the network".
  1886. X
  1887. X   SLNP is independant of a compression method (although most of the time 
  1888. X   "zip" is used, it is possible to have packets created by "zoo", "arc", or 
  1889. X   even simply "tar").
  1890. X
  1891. X   SLNP is also independant of the packet name (which is often machine 
  1892. X   dependant, like on dos you are limited to 8+3).
  1893. X   If possible the name should contain :
  1894. X   - The name of the server / BBS
  1895. X   - A sequence number or a date
  1896. X   - The packet type (SLNP)
  1897. X   - The compression or archive method used (.zip, .tar.Z etc...)
  1898. X
  1899. X   From those 3 informations the most important is probably the compression
  1900. X   method, because :
  1901. X   - Downloaded packets can be put in different directories for different
  1902. X   servers / BBS
  1903. X   - The date of the packet can be infered from the date of download
  1904. X   - The packet type has been negociated before download and there are less
  1905. X   packets types than compression methods.
  1906. X
  1907. X
  1908. X
  1909. X
  1910. X
  1911. 2) Anatomy of a packet
  1912. ======================
  1913. X
  1914. X
  1915. 2.1) List of files
  1916. ~~~~~~~~~~~~~~~~~~
  1917. X
  1918. The minimum requirement is a method to collect a group of files into a
  1919. single packet, and a method to expand the packet back into the original
  1920. files.  Each of the filenames in a packet should be stored in upper case on
  1921. those systems where case matters.
  1922. X
  1923. A packet consists of zero or more "message areas" (commonly called
  1924. "newsgroups" in USENET jargon).  Usually, each message area corresponds to
  1925. a different topic of discussion.
  1926. X
  1927. The following file specifications may appear in a packet:
  1928. X
  1929. INFO     : Optional textual information.
  1930. LIST     : Optional List of message areas on the generating system.
  1931. AREAS    : List of the message areas within the packet.
  1932. REPLIES  : Index of the reply message areas from the user.
  1933. *.MSG    : Text of the messages in a particular message area.
  1934. *.IDX    : Optional, Index information for messages in a message area.
  1935. COMMAND  : Optional, List of commands to be executed.
  1936. X
  1937. Other filenames may also appear in the packet, but are not defined by this
  1938. specification, so they should be avoided by generating software, and ignored
  1939. by receiving software.
  1940. X
  1941. The INFO file is an optional text file which may contain any kind of textual
  1942. information from the generating system.  Typically this file would only be
  1943. present if there is some kind of urgent message that must be sent to the
  1944. receiving user.  Use of this file to store the name of the generating BBS
  1945. and other such static information is possible, but discouraged to save space
  1946. and transmission time.  Lines in this text file are terminated by LF
  1947. characters (not by CR-LF pairs).
  1948. X
  1949. The LIST file contains a list of all message areas that are available on
  1950. the generating system, together with the format of the messages.  This is
  1951. an optional text file, with lines terminated by LF characters.  This should
  1952. only be sent to the receiving system upon user request.  It is specified
  1953. further in the section "LIST FILE".
  1954. X
  1955. The AREAS file contains an index of the message areas present within the
  1956. packet, specifying the name of the message area, the filename the messages
  1957. may be found in, and the message format.  This is specified further in the
  1958. next section.
  1959. X
  1960. The REPLIES file contains an index of the message areas present within the
  1961. packet that contain reply messages from a user which should be mailed or
  1962. posted on the receiving system (usually the system that packets are normally
  1963. downloaded from for off-line reading).  In most cases, a packet will contain
  1964. either an AREAS file or a REPLIES file, but both may be present.  See the
  1965. section "REPLIES FILE" below for more information.
  1966. X
  1967. The *.MSG files contain the text of the messages from a single message area.
  1968. The actual format of this file depends on the type of message area specified
  1969. in the AREAS file.  See the section "MESSAGE FILES" below for more information.
  1970.  
  1971. X
  1972. The *.IDX files provide an index into the *.MSG files, usually specifying
  1973. where each message starts and the contents of some of the common message
  1974. header fields.  These files are intended for use by reading software on the
  1975. recipient's system to quickly display an overview of the messages present in
  1976. a message area.  See the section "INDEX FILES" below for more information.
  1977. X
  1978. The COMMAND files is optional and contains the version information. If
  1979. absent version 1.1 is assumed. In future releases it may contain commands
  1980. to "subscribe" or "unsubscribe" to a message area.
  1981. X
  1982. X
  1983. 2.2 The AREAS file
  1984. ~~~~~~~~~~~~~~~~~~
  1985. X
  1986. The AREAS file is a text file containing zero or more lines, each of which
  1987. specifies a single message area, its type and the name of the message/index
  1988. file pair in which the messages appear. 
  1989. Lines are terminated with a single LF character (not CR-LF).
  1990. X
  1991. In particular, each line has the following form:
  1992. X
  1993. prefix<TAB>area name<TAB>type[<TAB>Optional fields]
  1994. X
  1995. Field   : prefix
  1996. Value   : Name of the message / index file for this area
  1997. Default : None, this field is mandatory
  1998. Example : "042" or "UNIX".
  1999. Comments: This name has to be kept short and without characters that may
  2000. not be recognised by some file systems. 
  2001. X
  2002. The message and index files corresponding to the message area have the names
  2003. "prefix.MSG" and "prefix.IDX" respectively.  If "prefix" contains alphabetic
  2004. characters, they must be upper case.
  2005. X
  2006. X
  2007. Field   : Area name
  2008. Value   : Any sequence of printable ASCII characters (space through tilde).
  2009. Default : None, this field is mandatory
  2010. Example : "comp.lang.c" or "C langage conference".
  2011. Comments: For usenet messages this will be the name of the newsgroup.
  2012. X
  2013. Although binary characters (ascii value > 127) are allowed, they can be used 
  2014. if the host and the home machine agree on a standard to represent them on 
  2015. the screen. This can be the case for example of accents or special
  2016. characters for non-english langages.
  2017. X
  2018. The only hard rule is that the name may not contain TAB, CR or LF.
  2019. Receiving software should treat the name as an indivisible string to be
  2020. displayed to the user.
  2021. X
  2022. X
  2023. Field   : type
  2024. Value   : two chars (see below)
  2025. Default : None, this field is mandatory
  2026. Example : "un" "uC" "Mc" ...
  2027. Comments: The first char describes the format of the message file (.MSG) and th
  2028. esecond char the format of the index file (.IDX).
  2029. X
  2030. The following message file formats are currently defined (case is significant):
  2031.  
  2032. X
  2033. u : USENET news articles
  2034. m : Unix mailbox articles
  2035. M : Mailbox articles in the MMDF format
  2036. b : Binary 8-bit clean mail format
  2037. B : Binary 8-bit clean news format
  2038. X
  2039. The individual message file encodings are explained further in the next
  2040. section.  The following index file formats are currently defined (again, case
  2041. is significant):
  2042. X
  2043. n : No index file
  2044. c : C-news overview database format
  2045. C : Shorter C-news overview database format
  2046. i : Offset/length pairs delineating the messages
  2047. X
  2048. These types are explained further in the section "INDEX FILES" below.
  2049. X
  2050. The optional fields are:
  2051. X
  2052. Field   : Description
  2053. Value   : Any sequence of printable ASCII characters (space through tilde).
  2054. Default : A null string
  2055. Example : "Telecommunications digest. (Moderated)"
  2056. Comments: For usenet messages this is often found in the file
  2057. /usr/lib/news/newsgroups.
  2058. Like for the "area name" field, binary characters should only appear if the
  2059. host and the home machine have agreed on a representation for them.
  2060. X
  2061. Field   : Number of messages
  2062. Value   : A numeric ascii string
  2063. Default : A null string
  2064. Example : "123"
  2065. Comments: This field can be used for example if no index file is given.
  2066. X
  2067. If an optional field is absent and it's follower is present then the <tab>
  2068. delimiter shall be present. For example :
  2069. X
  2070. Field1<tab>Field2<tab><tab>Field4 is valid while
  2071. Field1<tab>Field2<tab>Field4 is invalid 
  2072. X
  2073. Note that : Field1<tab><tab><tab> is valid but not necessary.
  2074. X
  2075. Further types may be defined in future versions of this specification.  If
  2076. the receiving software does not recognise a message file type, it should ignore
  2077.  
  2078. the corresponding message and index files.  If the receiving software does
  2079. not recognise a index file type, it can either ignore the message file, or
  2080. attempt to break down the message file into separate messages by some other
  2081. means.  The user should be warned if a message area has been ignored.
  2082. X
  2083. It is recommended that packet generation software support at least the index
  2084. file type 'C', since it gives the best compromise between transmission time
  2085. and assisting the reader software to display message area summaries.
  2086. X
  2087. X
  2088. A message area may appear more than once in the AREAS file, each time with a
  2089. different prefix, but this is discouraged.  This could be used to split large
  2090. message areas across more than one message file, but this is more conveniently
  2091. handled by generating a separate packet containing the area contination.
  2092. X
  2093. X
  2094. X
  2095. X
  2096. 2.3 Message Files
  2097. ~~~~~~~~~~~~~~~~~
  2098. X
  2099. The format of the message file depends on the message area type specified in
  2100. the AREAS file.  This version of the specification defines three formats,
  2101. which are in common use in the USENET and Unix community, and two additional
  2102. binary formats which permit messages to be stored with no modification or
  2103. assumptions about line lengths and byte values.
  2104. X
  2105. For each of first three formats, lines are terminated with LF characters.
  2106. Any CR characters in the messages should be considered as data characters, or
  2107. ignored on receipt.  In particular, MS-DOS systems should strip CR characters
  2108. >from text messages before writing them to a packet.
  2109. X
  2110. A 'u' (USENET) message file is a text file consisting of one or more messages
  2111. prefixed with an rnews header.  This header has the form "#! rnews n" where
  2112. "n" is the number of bytes in the message that follows the header, excluding
  2113. the line-feed character which terminates the header.  If the number in the
  2114. header is followed by white space and other characters, these other characters
  2115. should be ignored, until the terminating LF character is encountered.
  2116. X
  2117. A note about the rnews header: although a terser separator could be used, the
  2118. rnews header has the following advantages: (a) the messages can be extracted
  2119. in the absense of index files, or where the index files have an unknown type,
  2120. and (b) the message files can be imported into a USENET system as standard
  2121. rnews batches.  Thus, if the user wishes to set up a real USENET site, or
  2122. simply use dedicated USENET software to read packets, they can use their
  2123. existing packet provider as a convenient read-only newsfeed, with no extra
  2124. burden placed on the system administrator of the generating system.
  2125. X
  2126. A 'm' (Unix mailbox) message file is a text file consisting of one or more
  2127. messages.  The first line of each message must start with the character
  2128. sequence "From ".  Any remaining lines in the message which start with
  2129. "From " should have the character '>' prepended.  Thus the "From " lines
  2130. delimit the message file into separate messages.
  2131. X
  2132. A 'M' (MMDF mailbox) message file is a sequence of one or more messages,
  2133. separated by at least 4 Control-A characters.  The message file may optionally
  2134. start and end with a sequence of such characters.  If a sequence of 4 or more
  2135. Control-A characters occurs in a message, it should be "adjusted" by the
  2136. insertion of spaces to split the sequence.  The use of Control-A characters
  2137. within a message is discouraged.
  2138. X
  2139. The 'm' and 'M' formats were chosen for mail because of their common
  2140. occurrence in the Unix community.  The generating system may elect to instead
  2141. convert a mailbox into the USENET format if it wishes, and set the message area
  2142.  
  2143. name to some descriptive string to inform the reader.  It is recommended
  2144. however, that 'm' or 'M' be used for mail and 'u' for USENET news so that
  2145. reader software can make a distinction between the two if it wishes.
  2146. X
  2147. The 'b' (binary mail) and 'B' (binary news) formats are identical.  The
  2148. contents of each message must conform to RFC-822/1036 ([1]/[2]) and may
  2149. contain content information compatible with RFC-1341 ([3]).  The only
  2150. difference between the messages of these formats and the preceding formats
  2151. is that no assumption is made about line lengths, and any of the 256 values
  2152. for a byte may be used in any position.  Each message is preceded by a 4-
  2153. byte value which indicates the length of the message in bytes, stored in
  2154. big-endian order (i.e. high byte first, low byte last).  The difference
  2155. between 'b' and 'B' is a semantic one: message files of type 'b' are
  2156. expected to contain mail messages, and message files of type 'B' are
  2157. expected to contain news messages.  Thus, reader software can make a
  2158. distinction between the two if it desires.
  2159. X
  2160. For most practical purposes, 'u', 'm' and 'M' should be sufficient.  The binary
  2161.  
  2162. 'b' and 'B' types should be used for articles that contain 8-bit binary data.
  2163. It is possible to use type 'u' for binary data as well, but 'm' and 'M'
  2164. cannot be because the message contents may be modified.  When MIME becomes
  2165. more wide-spread, it is expected that binary messages containing programs,
  2166. sound, pictures and video will become popular, necessitating these binary
  2167. types.
  2168. X
  2169. Note that MIME messages can be stored in 'u', 'm' and 'M' message files, but
  2170. any binary components should be encoded with quoted-printable or base64 (which
  2171. is expected to be the most common usage of MIME in the near future).  It is
  2172. not required that 'b' or 'B' be used for MIME messages: only those containing
  2173. raw unencoded binary data (as indicated by the Content-transfer-encoding
  2174. header value "binary").
  2175. X
  2176. X
  2177. X
  2178. X
  2179. 2.4) Index Files
  2180. ~~~~~~~~~~~~~~~~
  2181. X
  2182. This specification defines four index file types, which provide varying
  2183. degrees of support for packet readers.
  2184. X
  2185. Type 'n' indicates that no index file is present, and it is up to the packet
  2186. reader to extract messages from the message file.  Use of this type is
  2187. discouraged, except where transmission time must be minimised (at the expense
  2188. of packet reader simplicity).  It may be useful where the generating system
  2189. is providing a USENET newsfeed using packets.
  2190. X
  2191. A type 'c' index file is a text file (LF terminated lines), with one line per
  2192. message that occurs in the message file.  The lines in the index file should
  2193. be in the same order as the corresponding messages.  Each line has the
  2194. following form:
  2195. X
  2196. offset<TAB>subject<TAB>author<TAB>date<TAB>mesgid<TAB>refs<TAB>bytes<TAB>lines
  2197. X
  2198. X
  2199. offset : Seek position in the message file of where the corresponding
  2200. message starts.  The first seek position is 0.  For the 'u'
  2201. format, this indicates the start of the line following the
  2202. rnews header line.  For the 'm' format, this indicates the
  2203. start of the "From " line and for the 'M' format, this
  2204. indicates the start of the article after the Control-A
  2205. sequence.  For the 'b' and 'B' formats, this indicates the
  2206. first byte of the message after the 4-byte message length.
  2207. X
  2208. subject : The "Subject:" line from the message.
  2209. X
  2210. author  : The "From:" line from the message.
  2211. X
  2212. date    : The "Date:" line from the message.
  2213. X
  2214. mesgid  : The "Message-Id:" line from the message.
  2215. X
  2216. refs    : The "References:" line from the message.
  2217. X
  2218. bytes   : The number of bytes in the message.
  2219. X
  2220. lines   : The "Lines:" line from the message.  Note that this field
  2221. is pretty useless these days on USENET, but is still popular.
  2222. It is meant to indicate the number of lines in the body of
  2223. the message.  Generating software may elect to re-generate
  2224. this value if it is not present in the original message,
  2225. but this is not required.
  2226. X
  2227. If any of these fields contained TAB's, newlines or other white space in the
  2228. SHAR_EOF
  2229. true || echo 'restore of slnr/slnp.fmt failed'
  2230. fi
  2231. echo 'End of  part 1'
  2232. echo 'File slnr/slnp.fmt is continued in part 2'
  2233. echo 2 > _shar_seq_.tmp
  2234. exit 0
  2235.  
  2236.  
  2237. --
  2238. Philippe Goujard <Sysop>                   Email : pgoujard@infocom.co.uk
  2239.   INFOCOM : FREE (yes free!) Usenet access in the UK - (0734) 34 00 55
  2240.  For more information mail "info@infocom.co.uk" a daemon will autoreply
  2241.  
  2242.